﻿using System.Security.Cryptography;
using System.Text;

namespace CocoaAni.Net.WebSockets.Tools;

public class WSHandShakeResponse : WSHttpHeadersHandler
{
    public string ProtocolVersion { get; set; } = "HTTP/1.1";
    public int StatusCode { get; set; } = 200;
    public string StatusCodeDescription { get; set; } = "(OK)";
    protected byte[]? Body { get; set; }

    public WSHandShakeResponse Parse(byte[] data)
    {
        var responseHeaderEndIndex = WSNetUtils.GetHttpHeaderEndIndex(data);
        if (responseHeaderEndIndex == -1)
        {
            throw new FormatException($"Http Response Is Not Has Double New Line!");
        }
        var responseHeader = Encoding.UTF8.GetString(data, 0, responseHeaderEndIndex - 1);
        var responseHeaderLines = responseHeader.Split("\r\n");
        var stateLine = responseHeaderLines[0];
        var stateLineData = stateLine.Split(' ');
        if (stateLineData.Length < 3)
        {
            throw new FormatException($"Http Response State Line Format Error => [{stateLine}]");
        }
        ProtocolVersion = stateLineData[0];
        StatusCode = int.Parse(stateLineData[1]);
        StatusCodeDescription = stateLine[stateLine.IndexOf(' ', 10)..];
        var headers = Headers;
        Headers = WSNetUtils.ParseHeaders(responseHeaderLines[1..], ref headers);
        if (responseHeaderEndIndex == data.Length - 1) return this;
        Body = data[(responseHeaderEndIndex + 1)..];
        return this;
    }

    public WSHandShakeResponse()
    {
    }

    public byte[] Build()
    {
        var requestLine = $"{ProtocolVersion} {StatusCode} {StatusCodeDescription}";
        var sb = new StringBuilder();
        sb.Append(requestLine).AppendLine();
        foreach (var (key, value) in Headers)
        {
            switch (value)
            {
                case string strValue:
                    sb.Append($"{key}: {value}{Environment.NewLine}");
                    break;

                case IEnumerable<string> values:
                    {
                        sb.Append(key).Append(": ");
                        foreach (var s in values)
                        {
                            sb.AppendLine($"{s}; {Environment.NewLine}");
                        }
                        break;
                    }
            }
        }
        sb.AppendLine();
        return Encoding.UTF8.GetBytes(sb.ToString());
    }

    public static WSHandShakeResponse CreateOk(string key)
    {
        var encryptionString =
            SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
        var resp = new WSHandShakeResponse()
        {
            Headers = new Dictionary<string, object>()
            {
                { "Upgrade", "websocket" },
                { "Connection", "Upgrade" },
                { "Sec-WebSocket-Accept", Convert.ToBase64String(encryptionString) }
            }
        };
        resp.StatusCodeDescription = "Switching Protocols";
        resp.StatusCode = 101;
        return resp;
    }
}